/*
* Copyright (C) 2014 The Calrissian Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.calrissian.accumulorecipes.eventstore.impl;
import static com.google.common.collect.Iterables.get;
import static com.google.common.collect.Iterables.size;
import static com.google.common.io.Resources.getResource;
import static java.lang.System.currentTimeMillis;
import static java.nio.charset.Charset.defaultCharset;
import static java.util.Collections.sort;
import static org.calrissian.mango.json.util.store.JsonAttributeStore.fromJson;
import static org.junit.Assert.assertEquals;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.collect.Sets;
import com.google.common.io.Resources;
import org.apache.accumulo.core.client.AccumuloException;
import org.apache.accumulo.core.client.AccumuloSecurityException;
import org.apache.accumulo.core.client.Connector;
import org.apache.accumulo.core.client.TableExistsException;
import org.apache.accumulo.core.client.TableNotFoundException;
import org.calrissian.accumulorecipes.commons.domain.Auths;
import org.calrissian.accumulorecipes.eventstore.EventStore;
import org.calrissian.accumulorecipes.test.AccumuloMiniClusterDriver;
import org.calrissian.accumulorecipes.test.AccumuloTestUtils;
import org.calrissian.mango.collect.CloseableIterable;
import org.calrissian.mango.criteria.builder.QueryBuilder;
import org.calrissian.mango.criteria.domain.Node;
import org.calrissian.mango.domain.Attribute;
import org.calrissian.mango.domain.event.Event;
import org.calrissian.mango.domain.event.EventBuilder;
import org.calrissian.mango.json.util.store.JsonAttributeStore.FlattenedLevelsComparator;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Test;
/**
* A real-world example to test storage/query of twitter json.
* @throws Exception
*/
public class JsonEventStoreIT {
@ClassRule
public static AccumuloMiniClusterDriver accumuloMiniClusterDriver = new AccumuloMiniClusterDriver();
private static FlattenedLevelsComparator comparator = new FlattenedLevelsComparator();
private EventStore store;
private ObjectMapper objectMapper = new ObjectMapper();
@Before
public void setup() throws AccumuloSecurityException, AccumuloException, TableNotFoundException, TableExistsException {
accumuloMiniClusterDriver.deleteAllTables();
store = new AccumuloEventStore(getConnector());
}
@Test
public void testTwitterJson() throws Exception {
List<Event> eventList = new ArrayList<Event>();
/**
* First, we'll load a json object representing tweets
*/
String tweetJson = Resources.toString(getResource("twitter_tweets.json"), defaultCharset());
/**
* Create tweet event with a random UUID and timestamp of current time
* (both of these can be set manually in the constructor)
*/
Event tweetEvent = EventBuilder.create("tweet", UUID.randomUUID().toString(), System.currentTimeMillis())
.attrs(fromJson(tweetJson, objectMapper)).build();
eventList.add(tweetEvent);
/**
* Next, we'll load a json array containing user timeline data
*/
String timelineJson = Resources.toString(getResource("twitter_timeline.json"), defaultCharset());
/**
* Since we need to persist objects, we'll loop through the array and create
* events out of the objects
*/
ArrayNode node = (ArrayNode) objectMapper.readTree(timelineJson);
for(JsonNode node1 : node) {
// create an event from the current json object
Event timelineEvent = EventBuilder.create("tweet", UUID.randomUUID().toString(), System.currentTimeMillis())
.attrs(fromJson((ObjectNode) node1)).build();
eventList.add(timelineEvent);
}
/**
* Save events in the event store and flush
*/
store.save(eventList);
store.flush();
AccumuloTestUtils.dumpTable(getConnector(), "eventStore_shard");
/**
* Build our query to retrieve stored events by their flattened json
* representation.
*/
Node query = QueryBuilder.create()
.and()
.eq("statuses_$entities_$hashtags_$indices", 29) // the json tree has been flattened
.eq("statuses_$user_$name", "Sean Cummings") // into key/value objects
.end()
.build();
CloseableIterable<Event> results = store.query(
new Date(0),
new Date(currentTimeMillis()),
Sets.newHashSet("tweet"),
query,
Auths.EMPTY
);
assertEquals(1, size(results));
List<Attribute> expectedAttributes = new ArrayList(tweetEvent.getAttributes());
List<Attribute> actualAttributes = new ArrayList<Attribute>(get(results, 0).getAttributes());
sort(expectedAttributes, comparator);
sort(actualAttributes, comparator);
assertEquals(expectedAttributes, actualAttributes);
}
public static Connector getConnector() throws AccumuloSecurityException, AccumuloException {
return accumuloMiniClusterDriver.getConnector();
}
}